package com.thh.shirodemo.service;

import com.thh.shirodemo.bean.Deal;
import com.thh.shirodemo.mapper.DealMapper;
import com.thh.shirodemo.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;


/**
 * @author shkstart
 * @create 2022-07-28-0:00
 */
@Service
public class SeckillService {
    //2.连接radis
    @Autowired
    RedisUtil redisUtil;

    @Autowired
    DealMapper dealMapper;

    @Autowired
    RedisTemplate redisTemplate;

    //RedisUtil执行秒杀活动(多线程问题) 乐观锁解决:超卖问题 lua脚本:库存遗留问题
    public  String doSecKill1(Integer userId,String userName,String prodName){
        //1.当数据库中没有开启秒杀活动
        if(prodName==null) return "还没有秒杀活动";
        //2.连接radis
        //3.拼接key
        //3.1库存key
        String kcKey="sk:"+prodName+"count";
        //3.2秒杀成功用户key
        String userKey="sk:"+prodName+"user";

        //4.判断用户是否重复秒杀
        if(redisUtil.sismember(userKey,userName)){
            //已经存在
            return "您已经秒杀成功了，不能重复操作";
        }
        //库存
        Integer kc=(Integer)redisUtil.get(kcKey);
        //5.库存小于1 秒杀结束
        if (kc<=0){
            return "秒杀已经结束了";
        }
        //6.1秒杀过程 库存-1
        redisUtil.decr(kcKey,1);
        //6.2秒杀成功用户添加到清单里面
        redisUtil.sadd(userKey,userName);
        //6.3mysql持久层中添加商品
        dealMapper.insert(new Deal(prodName,userId));
        return "恭喜你秒杀成功";
    }

    //RedisTemplate执行秒杀活动 乐观锁解决:超卖问题 lua脚本:库存遗留问题
    public  String doSecKill(Integer userId,String userName,String prodName){
        //1.当数据库中没有开启秒杀活动
        if(prodName==null) return "还没有秒杀活动";
        //2.连接radis
        //3.拼接key
        //3.1库存key
        String kcKey="sk:"+prodName+"count";
        //3.2秒杀成功用户key
        String userKey="sk:"+prodName+"user";

        /*redisTemplate 开启事务支持*/
        redisTemplate.setEnableTransactionSupport(true);
        //监视库存
        redisTemplate.watch(kcKey);

        //4.判断用户是否重复秒杀
        if(redisTemplate.opsForSet().isMember(userKey,userName)){
            //已经存在
            return "您已经秒杀成功了，不能重复操作";
        }
        //库存
        Integer kc=(Integer)redisTemplate.opsForValue().get(kcKey);
        //5.库存小于1 秒杀结束
        if (kc<=0){
            return "秒杀已经结束了";
        }

        //组队操作
        redisTemplate.multi();
        //6.1秒杀过程 库存-1
        redisTemplate.opsForValue().increment(kcKey,-1);
        //6.2秒杀成功用户添加到清单里面
        redisTemplate.opsForSet().add(userKey,userName);
        //事务结束
        redisTemplate.exec();

        //6.3mysql持久层中添加商品
        dealMapper.insert(new Deal(prodName,userId));
        return "恭喜你秒杀成功";
    }


    /**
     * 以下是用于测试的秒杀方法
     */

    /**
     * 最普通的没有任何锁 会漏卖
     * @return
     */
    public  String doSecKillT1(){
        String kcKey="sk:Iphone13count";

        /*redisTemplate 开启事务支持*/
        redisTemplate.setEnableTransactionSupport(true);
        //监视库存
        redisTemplate.watch(kcKey);

        //库存
        Integer kc=(Integer)redisTemplate.opsForValue().get(kcKey);
        //5.库存小于1 秒杀结束
        if (kc<=0){
            System.out.println("秒杀已经结束了");
            return "秒杀已经结束了";
        }
        //组队操作
        redisTemplate.multi();
        //6.1秒杀过程 库存-1
        redisTemplate.opsForValue().increment(kcKey,-1);
        //事务结束
        redisTemplate.exec();
        System.out.println("恭喜你秒杀成功");
        return "恭喜你秒杀成功";
    }

    /**
     * 加上别悲观锁 解决超卖
     * 会造成线程阻塞，线程排队问题
     */
    public  String doSecKillT2(){
        String kcKey="sk:Iphone13count";
        try {
            //使用悲观锁
            synchronized (this){
                //库存
                Integer kc=(Integer)redisTemplate.opsForValue().get(kcKey);
                //5.库存小于1 秒杀结束
                if (kc<=0){
                    System.out.println("秒杀已经结束了");
                    return "秒杀已经结束了";
                }
                //6.1秒杀过程 库存-1
                redisTemplate.opsForValue().increment(kcKey,-1);
                System.out.println("恭喜你秒杀成功");
                return "恭喜你秒杀成功";
            }
        }catch (Exception e){
            System.out.println("出现异常");
        }
        return "异常";
    }

    /**
     * 加上乐观锁解决漏卖 但是会超卖
     * @return
     */
    public  String doSecKillT3(){
        String kcKey="sk:Iphone13count";

        /*redisTemplate 开启事务支持*/
        redisTemplate.setEnableTransactionSupport(true);
        //监视库存
        redisTemplate.watch(kcKey);

        //库存
        Integer kc=(Integer)redisTemplate.opsForValue().get(kcKey);
        //5.库存小于1 秒杀结束
        if (kc<=0){
            System.out.println("秒杀已经结束了");
            return "秒杀已经结束了";
        }
        //组队操作
        redisTemplate.multi();
        //6.1秒杀过程 库存-1
        redisTemplate.opsForValue().increment(kcKey,-1);
        //事务结束
        redisTemplate.exec();
        System.out.println("恭喜你秒杀成功");
        return "恭喜你秒杀成功";
    }

    /**
     * 乐观锁+lua脚本
     * 通过lua脚本解决争抢问题，实际上是redis 利用其单线程的特性，用任务队列的方式解决多任务并发问题。
     */
    public  String doSecKillT4(){
        String kcKey="sk:Iphone13count";

        /*redisTemplate 开启事务支持*/
        redisTemplate.setEnableTransactionSupport(true);
        //监视库存
        redisTemplate.watch(kcKey);

        //库存
        Integer kc=(Integer)redisTemplate.opsForValue().get(kcKey);
        //5.库存小于1 秒杀结束
        if (kc<=0){
            System.out.println("秒杀已经结束了");
            return "秒杀已经结束了";
        }
        //组队操作
        redisTemplate.multi();
        //6.1秒杀过程 库存-1
        redisTemplate.opsForValue().increment(kcKey,-1);
        //事务结束
        redisTemplate.exec();
        System.out.println("恭喜你秒杀成功");
        return "恭喜你秒杀成功";
    }
}
